#[derive(Debug, PartialEq)]
pub enum Node {
    Number(i64),
    BinaryOp {
        left: Box<Node>,
        operator: char,
        right: Box<Node>,
    },
}

pub fn parse(tokens: Vec<Token>) -> Result<Node, String> {
    let mut tokens = tokens.into_iter().peekable();
    parse_expression(&mut tokens)
}

fn parse_expression(tokens &mut std::iter::Peekable<std::IntoIter<Token>>) 
    -> Result<Node, String> {
        let mut left = parse_term(tokens)?;

        while let Some(op) = tokens.peek() {
            match op {
                Token::Operator('+') | Token::Operator('-') => {
                    let op = if let Token::Operator(op) = 
                        tokens.next().unwrap() {
                            op
                        } else {
                            unreachable!()
                        };

                    let right = parse_term(tokens)?;
                    left = Node::BinaryOp {
                        left: Box::new(left),
                        operator: op,
                        right: Box::new(right),
                    };
                }
                _ => break,
            }
        }

        Ok(left)
    }

fn parse_term(tokens: &mut std::iter::Peekable<std::vec::IntoIter<Token>>) 
    -> Result<Node, String> {
        let mut left = parse_factor(tokens)?;

        while let Some(op) = tokens.peek() {
            match op {
                Token::Operator('*') | Token::Operator('/') => {
                    let op = if let Token::Operator(op) = 
                        tokens.next().unwrap() {
                            op
                        } else {
                            unreachable!()
                        };

                    let right = parse_factor(tokens)?;

                    left = Node::BinaryOp {
                        left: Box::new(left),
                        operator: op,
                        right: Box::new(right),
                    };
                },
                _ => break,
            }
        }

        Ok(left)
    }

fn parse_factor(tokens: &mut
    std::iter::Peekable<std::vec::IntoIter<Token>>) -> Result<Node, String> {
    match tokens.next() {
        Some(Token::Integer(value)) => Ok(Node::Number(value)),
        _ => Err("Expected integer".to_string()),
    }
}
